home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1999 March / EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso / earcd / misc / pdflib / p_gif_original.c < prev    next >
C/C++ Source or Header  |  1999-01-01  |  13KB  |  567 lines

  1. /* p_gif.c
  2.  * Copyright (C) 1997-98 Thomas Merz. All rights reserved.
  3.  *
  4.  * GIF processing for PDFlib
  5.  */
  6.  
  7. /* 
  8.  * This module is basically a rewrite of David Koblas' giftoppm.c,
  9.  * taken from the PBMPLUS package. It contained the following notice:
  10.  */
  11.  
  12. /* +-------------------------------------------------------------------+ */
  13. /* | Copyright 1990, David Koblas.                                     | */
  14. /* |   Permission to use, copy, modify, and distribute this software   | */
  15. /* |   and its documentation for any purpose and without fee is hereby | */
  16. /* |   granted, provided that the above copyright notice appear in all | */
  17. /* |   copies and that both that copyright notice and this permission  | */
  18. /* |   notice appear in supporting documentation.  This software is    | */
  19. /* |   provided "as is" without express or implied warranty.           | */
  20. /* +-------------------------------------------------------------------+ */
  21.  
  22. #include <string.h>
  23.  
  24. #include "p_intern.h"
  25.  
  26. #define CM_RED            0
  27. #define CM_GREEN        1
  28. #define CM_BLUE            2
  29.  
  30. #define    MAX_LWZ_BITS        12
  31.  
  32. #define INTERLACE        0x40
  33. #define LOCALCOLORMAP        0x80
  34. #define BitSet(byte, bit)    (((byte) & (bit)) == (bit))
  35.  
  36. #define    ReadOK(file,buffer,len)    (fread(buffer, len, 1, file) != 0)
  37.  
  38. #define LM_to_uint(a,b)            (((b)<<8)|(a))
  39.  
  40. static int ReadColorMap(FILE *fp, int number, pdf_colormap buffer);
  41. static int DoExtension(PDF *p, PDF_image *image, int label);
  42. static int GetDataBlock(FILE *fp, unsigned char  *buf);
  43. static void ReadImage(PDF *p, PDF_image *image, PDF_data_source *src, int ignore);
  44.  
  45. /* imported via strange #include due to licensing issues... */
  46. int GetCode(FILE *fp, int code_size, int flag);
  47. int LWZReadByte(FILE *fd, int flag, int input_code_size);
  48.  
  49. static void
  50. pdf_data_source_GIF_init(PDF *p, PDF_data_source *src)
  51. {
  52.     PDF_image        *image;
  53.  
  54.     image = (PDF_image *) src->private_data;
  55.  
  56.     src->buffer_length    = image->width * image->height * 1;
  57.     src->buffer_start    = 
  58.         (byte*) PDF_malloc(src->buffer_length, "pdf_data_source_GIF_init");
  59.     src->bytes_available= 0;
  60.     src->next_byte    = NULL;
  61.  
  62.     if (!image->useGlobalColormap) {
  63.     if (ReadColorMap(image->fp, image->bitPixel, image->colormap)) {
  64.         pdf_error(p, PDF_WARN, "Error reading local colormap");
  65.         return;
  66.     }
  67.     }
  68. }
  69.  
  70. static bool
  71. pdf_data_source_GIF_fill(PDF *p, PDF_data_source *src)
  72. {
  73.     PDF_image    *image;
  74.  
  75.     if (src->next_byte != NULL)        /* all finished in one turn */
  76.     return false;
  77.  
  78.     image = (PDF_image *) src->private_data;
  79.  
  80.     src->next_byte = src->buffer_start;
  81.     src->bytes_available = src->buffer_length;
  82.  
  83.     ReadImage(p, image, src, false);
  84.  
  85.     return true;
  86. }
  87.  
  88. static void
  89. pdf_data_source_GIF_terminate(PDF *p, PDF_data_source *src)
  90. {
  91.   PDF_free((void *) src->buffer_start);
  92. }
  93.  
  94. PDF_image *
  95. PDF_open_GIF(PDF *p, char *filename)
  96. {
  97.     unsigned char    buf[16];
  98.     char    c;
  99.     int        imageCount = 0;
  100.     char    version[4];
  101.     int        imageNumber = 1;    /* HACK:read only first image */
  102.     PDF_image    *image;
  103.     
  104.     image = (PDF_image *) PDF_malloc(sizeof(PDF_image), "PDF_open_GIF");
  105.  
  106.     if (image == NULL)
  107.     return NULL;
  108.  
  109.     image->filename    = filename;
  110.     image->compression    = none;
  111.     image->closefunc    = PDF_close_GIF;
  112.  
  113.     if ((image->fp = fopen(image->filename, READMODE)) == NULL) {
  114.     pdf_error(p, PDF_WARN, "Couldn't open GIF file %s", image->filename);
  115.     PDF_free(image);
  116.     return NULL;
  117.     }
  118.  
  119.     if (! ReadOK(image->fp,buf,6)) {
  120.     pdf_error(p, PDF_WARN, "Error reading magic number" );
  121.     return NULL;
  122.     }
  123.  
  124.     if (strncmp((const char *) buf, "GIF",3) != 0) {
  125.     pdf_error(p, PDF_WARN, "Not a GIF file" );
  126.     return NULL;
  127.     }
  128.  
  129.     strncpy(version, (const char *) buf + 3, 3);
  130.     version[3] = '\0';
  131.  
  132.     if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
  133.     pdf_error(p, PDF_WARN, "Bad version number" );
  134.     return NULL;
  135.     }
  136.  
  137.     if (! ReadOK(image->fp,buf,7)) {
  138.     pdf_error(p, PDF_WARN, "Failed to read screen descriptor" );
  139.     return NULL;
  140.     }
  141.  
  142.     /* size of the global color table*/
  143.     image->BitPixel        = 2<<(buf[4]&0x07);
  144.  
  145.     if (BitSet(buf[4], LOCALCOLORMAP)) {    /* Global Colormap */
  146.     if (ReadColorMap(image->fp, image->BitPixel, image->colormap)) {
  147.         pdf_error(p, PDF_WARN, "Error reading global colormap");
  148.         return NULL;
  149.     }
  150.     }
  151.  
  152. #ifdef ORIG
  153.     if (image->AspectRatio != 0 && image->AspectRatio != 49) {
  154.     float    r;
  155.     r = ( (float) image->AspectRatio + 15.0 ) / 64.0;
  156.     /*pm_message("warning - non-square pixels");*/
  157.     }
  158. #endif
  159.  
  160.     for (;;) {
  161.     if (! ReadOK(image->fp,&c,1)) {
  162.         pdf_error(p, PDF_WARN, "EOF / read error on image data" );
  163.         return NULL;
  164.     }
  165.  
  166.     if (c == ';') {        /* GIF terminator */
  167.         if (imageCount < imageNumber) {
  168.         pdf_error(p, PDF_WARN, "Only %d image%s found in file",
  169.              imageCount, imageCount > 1?"s":"" );
  170.         return NULL;
  171.         }
  172.         break;
  173.     }
  174.  
  175.     if (c == '!') {     /* Extension */
  176.         if (! ReadOK(image->fp,&c,1)) {
  177.         pdf_error(p, PDF_INFO, 
  178.             "EOF / read error on extension function code");
  179.         return NULL;
  180.         }
  181.         DoExtension(p, image, c);
  182.         continue;
  183.     }
  184.  
  185.     if (c != ',') {        /* Not a valid start character */
  186.         pdf_error(p, PDF_WARN,
  187.         "Bogus character 0x%02x, ignoring", (int) c);
  188.         continue;
  189.     }
  190.  
  191.     ++imageCount;
  192.  
  193.     if (! ReadOK(image->fp,buf,9)) {
  194.         pdf_error(p, PDF_WARN, 
  195.         "Couldn't read left/top/width/height");
  196.         return NULL;
  197.     }
  198.  
  199.     image->colorspace = DeviceRGB;    /* HACK */
  200.     image->indexed = true;
  201.     image->components = 3;        /* HACK */
  202.     image->bpc = 8;            /* HACK */
  203.     image->width    = LM_to_uint(buf[4],buf[5]);
  204.     image->height    = LM_to_uint(buf[6],buf[7]);
  205.     image->useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
  206.     image->bitPixel = 1<<((buf[8]&0x07)+1);
  207.     image->interlace= BitSet(buf[8], INTERLACE);
  208.  
  209.     if (imageCount == 1)
  210.         break;
  211.     }
  212.     
  213.     image->src.init        = pdf_data_source_GIF_init;
  214.     image->src.fill        = pdf_data_source_GIF_fill;
  215.     image->src.terminate    = pdf_data_source_GIF_terminate;
  216.     image->src.private_data    = (void *) image;
  217.  
  218.     return image;
  219. }
  220.  
  221. void
  222. PDF_close_GIF(PDF *p, PDF_image *image)
  223. {
  224.     fclose(image->fp);
  225. }
  226.  
  227. static int
  228. ReadColorMap(FILE *fp, int number, pdf_colormap buffer)
  229. {
  230.     int        i;
  231.     unsigned char    rgb[3];
  232.  
  233.     for (i = 0; i < number; ++i) {
  234.         if (! ReadOK(fp, rgb, sizeof(rgb))) {
  235.         return true;
  236.         }
  237.  
  238.         buffer[i][0] = rgb[0] ;
  239.         buffer[i][1] = rgb[1] ;
  240.         buffer[i][2] = rgb[2] ;
  241.     }
  242.     return false;
  243. }
  244.  
  245. static int
  246. DoExtension(PDF *p, PDF_image *image, int label)
  247. {
  248.     static char    buf[256];
  249.     char        *str;
  250.  
  251.     switch (label) {
  252.     case 0x01:        /* Plain Text Extension */
  253.         str = "Plain Text Extension";
  254. #ifdef notdef
  255.         if (GetDataBlock(image->fp, (unsigned char*) buf) == 0)
  256.             ;
  257.  
  258.         lpos   = LM_to_uint(buf[0], buf[1]);
  259.         tpos   = LM_to_uint(buf[2], buf[3]);
  260.         width  = LM_to_uint(buf[4], buf[5]);
  261.         height = LM_to_uint(buf[6], buf[7]);
  262.         cellw  = buf[8];
  263.         cellh  = buf[9];
  264.         foreground = buf[10];
  265.         background = buf[11];
  266.  
  267.         while (GetDataBlock(image->fp, (unsigned char*) buf) != 0) {
  268.             PPM_ASSIGN(image[ypos][xpos],
  269.                     cmap[v][CM_RED],
  270.                     cmap[v][CM_GREEN],
  271.                     cmap[v][CM_BLUE]);
  272.             ++index;
  273.         }
  274.  
  275.         return false;
  276. #else
  277.         break;
  278. #endif
  279.     case 0xff:        /* Application Extension */
  280.         str = "Application Extension";
  281.         break;
  282.     case 0xfe:        /* Comment Extension */
  283.         str = "Comment Extension";
  284.         while (GetDataBlock(image->fp, (unsigned char*) buf) != 0) {
  285.             /*pm_message("gif comment: %s", buf );*/
  286.         }
  287.         return false;
  288.     case 0xf9:        /* Graphic Control Extension */
  289.         str = "Graphic Control Extension";
  290.         (void) GetDataBlock(image->fp, (unsigned char*) buf);
  291.         image->disposal    = (buf[0] >> 2) & 0x7;
  292.         image->inputFlag   = (buf[0] >> 1) & 0x1;
  293.         image->delayTime   = LM_to_uint(buf[1],buf[2]);
  294.         if ((buf[0] & 0x1) != 0)
  295.             image->transparent = buf[3];
  296.  
  297.         while (GetDataBlock(image->fp, (unsigned char*) buf) != 0)
  298.             ;
  299.         return false;
  300.     default:
  301.         str = buf;
  302.         sprintf(buf, "UNKNOWN (0x%02x)", label);
  303.         break;
  304.     }
  305.  
  306.     /*pm_message("got a '%s' extension", str );*/
  307.  
  308.     while (GetDataBlock(image->fp, (unsigned char*) buf) != 0)
  309.         ;
  310.  
  311.     return false;
  312. }
  313.  
  314. static int    ZeroDataBlock = false;
  315.  
  316. static int
  317. GetDataBlock(FILE *fp, unsigned char *buf)
  318. {
  319.     unsigned char    count;
  320.  
  321.     if (! ReadOK(fp,&count,1)) {
  322.         /*pdf_error(p, PDF_WARN, "Error in getting DataBlock size" );*/
  323.         return -1;
  324.     }
  325.  
  326.     ZeroDataBlock = count == 0;
  327.  
  328.     if ((count != 0) && (! ReadOK(fp, buf, count))) {
  329.         /*pdf_error(p, PDF_WARN, "Error in reading DataBlock" );*/
  330.         return -1;
  331.     }
  332.  
  333.     return count;
  334. }
  335.  
  336. /* Dummies for LZW code */
  337. #define pm_message(x)    /* */
  338. #define pm_error(x)    /* */
  339.  
  340. int
  341. GetCode(FILE *fp, int code_size, int flag)
  342. {
  343.     static unsigned char    buf[280];
  344.     static int        curbit, lastbit, done, last_byte;
  345.     int            i, j, ret;
  346.     unsigned char        count;
  347.  
  348.     if (flag) {
  349.         curbit = 0;
  350.         lastbit = 0;
  351.         done = false;
  352.         return 0;
  353.     }
  354.  
  355.     if ( (curbit+code_size) >= lastbit) {
  356.         if (done) {
  357.             if (curbit >= lastbit)
  358.                 pm_error("ran off the end of my bits" );
  359.             return -1;
  360.         }
  361.         buf[0] = buf[last_byte-2];
  362.         buf[1] = buf[last_byte-1];
  363.  
  364.         if ((count = GetDataBlock(fp, &buf[2])) == 0)
  365.             done = true;
  366.  
  367.         last_byte = 2 + count;
  368.         curbit = (curbit - lastbit) + 16;
  369.         lastbit = (2+count)*8 ;
  370.     }
  371.  
  372.     ret = 0;
  373.     for (i = curbit, j = 0; j < code_size; ++i, ++j)
  374.         ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
  375.  
  376.     curbit += code_size;
  377.  
  378.     return ret;
  379. }
  380.  
  381. int
  382. LWZReadByte(FILE *fd, int flag, int input_code_size)
  383. {
  384.     static int    fresh = false;
  385.     int        code, incode;
  386.     static int    code_size, set_code_size;
  387.     static int    max_code, max_code_size;
  388.     static int    firstcode, oldcode;
  389.     static int    clear_code, end_code;
  390.     static int    table[2][(1<< MAX_LWZ_BITS)];
  391.     static int    stack[(1<<(MAX_LWZ_BITS))*2], *sp;
  392.     register int    i;
  393.  
  394.     if (flag) {
  395.         set_code_size = input_code_size;
  396.         code_size = set_code_size+1;
  397.         clear_code = 1 << set_code_size ;
  398.         end_code = clear_code + 1;
  399.         max_code_size = 2*clear_code;
  400.         max_code = clear_code+2;
  401.  
  402.         GetCode(fd, 0, true);
  403.         
  404.         fresh = true;
  405.  
  406.         for (i = 0; i < clear_code; ++i) {
  407.             table[0][i] = 0;
  408.             table[1][i] = i;
  409.         }
  410.         for (; i < (1<<MAX_LWZ_BITS); ++i)
  411.             table[0][i] = table[1][0] = 0;
  412.  
  413.         sp = stack;
  414.  
  415.         return 0;
  416.     } else if (fresh) {
  417.         fresh = false;
  418.         do {
  419.             firstcode = oldcode =
  420.                 GetCode(fd, code_size, false);
  421.         } while (firstcode == clear_code);
  422.         return firstcode;
  423.     }
  424.  
  425.     if (sp > stack)
  426.         return *--sp;
  427.  
  428.     while ((code = GetCode(fd, code_size, false)) >= 0) {
  429.         if (code == clear_code) {
  430.             for (i = 0; i < clear_code; ++i) {
  431.                 table[0][i] = 0;
  432.                 table[1][i] = i;
  433.             }
  434.             for (; i < (1<<MAX_LWZ_BITS); ++i)
  435.                 table[0][i] = table[1][i] = 0;
  436.             code_size = set_code_size+1;
  437.             max_code_size = 2*clear_code;
  438.             max_code = clear_code+2;
  439.             sp = stack;
  440.             firstcode = oldcode =
  441.                     GetCode(fd, code_size, false);
  442.             return firstcode;
  443.         } else if (code == end_code) {
  444.             int        count;
  445.             unsigned char    buf[260];
  446.  
  447.             if (ZeroDataBlock)
  448.                 return -2;
  449.  
  450.             while ((count = GetDataBlock(fd, buf)) > 0)
  451.                 ;
  452.  
  453.             if (count != 0)
  454.                 pm_message("missing EOD in data stream (common occurence)");
  455.             return -2;
  456.         }
  457.  
  458.         incode = code;
  459.  
  460.         if (code >= max_code) {
  461.             *sp++ = firstcode;
  462.             code = oldcode;
  463.         }
  464.  
  465.         while (code >= clear_code) {
  466.             *sp++ = table[1][code];
  467.             if (code == table[0][code])
  468.                 pm_error("circular table entry BIG ERROR");
  469.             code = table[0][code];
  470.         }
  471.  
  472.         *sp++ = firstcode = table[1][code];
  473.  
  474.         if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
  475.             table[0][code] = oldcode;
  476.             table[1][code] = firstcode;
  477.             ++max_code;
  478.             if ((max_code >= max_code_size) &&
  479.                 (max_code_size < (1<<MAX_LWZ_BITS))) {
  480.                 max_code_size *= 2;
  481.                 ++code_size;
  482.             }
  483.         }
  484.  
  485.         oldcode = incode;
  486.  
  487.         if (sp > stack)
  488.             return *--sp;
  489.     }
  490.     return code;
  491. }
  492.  
  493.  
  494. static void
  495. ReadImage(PDF *p, PDF_image *image, PDF_data_source *src, int ignore)
  496. {
  497.     unsigned char    c;    
  498.     int        v;
  499.     int        xpos = 0, ypos = 0, pass = 0;
  500.     byte        *dest;
  501.  
  502.     /*
  503.     **  Initialize the Compression routines
  504.     */
  505.     if (! ReadOK(image->fp,&c,1))
  506.         pm_error("EOF / read error on image data" );
  507.  
  508.     if (LWZReadByte(image->fp, true, c) < 0)
  509.         pm_error("error reading image" );
  510.  
  511.     /*
  512.     **  If this is an "uninteresting picture" ignore it.
  513.     */
  514.     if (ignore) {
  515.         pdf_error(p, PDF_INFO, "Skipping image..." );
  516.         while (LWZReadByte(image->fp, false, c) >= 0)
  517.             ;
  518.         return;
  519.     }
  520.  
  521.     dest = src->buffer_start;
  522.     while ((v = LWZReadByte(image->fp,false,c)) >= 0 ) {
  523.  
  524.         *dest++ = v;    /* fetch pixel value */
  525.         ++xpos;
  526.  
  527.         if (xpos == image->width) {
  528.             xpos = 0;
  529.  
  530.             if (image->interlace) {
  531.                 switch (pass) {
  532.                 case 0:
  533.                 case 1:
  534.                     ypos += 8; break;
  535.                 case 2:
  536.                     ypos += 4; break;
  537.                 case 3:
  538.                     ypos += 2; break;
  539.                 }
  540.  
  541.                 if (ypos >= image->height) {
  542.                     ++pass;
  543.                     switch (pass) {
  544.                     case 1:
  545.                         ypos = 4; break;
  546.                     case 2:
  547.                         ypos = 2; break;
  548.                     case 3:
  549.                         ypos = 1; break;
  550.                     default:
  551.                         goto fini;
  552.                     }
  553.                 }
  554.             } else {
  555.                 ++ypos;
  556.             }
  557.             dest = src->buffer_start + ypos * image->width;
  558.         }
  559.         if (ypos >= image->height)
  560.             break;
  561.     }
  562.  
  563. fini:
  564.     if (LWZReadByte(image->fp,false,c)>=0)
  565.         pdf_error(p, PDF_WARN, "Too much input data, ignoring extra.");
  566. }
  567.